package com.quick.proxy.core.utils;

import com.quick.proxy.core.ProtocolConstants;
import com.quick.proxy.core.ProxyMessage;

import java.security.SecureRandom;
import java.util.Arrays;

/**
 * Description: 协议工具类
 * Author: 吃素不吃肉
 * Date: 2023/7/4
 *
 * @author 吃素不吃肉
 */
public class ProtocolUtils {
    private static final int[] RS_CTL = {0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78};
    private static final int STX = 0x55aa;

    public static int getRsCtl() {
        return RS_CTL[new SecureRandom().nextInt(RS_CTL.length)];
    }

    /**
     * 构建发送数据帧报文格式
     *
     * @param cmd  指令类型 16进制
     * @param data 数据
     * @return 数据帧字节数组
     */
    public static byte[] getByte(int cmd, byte[] data) {
        return getByte(cmd, data, false);
    }


    /**
     * 构建发送数据帧报文格式
     *
     * @param cmd          指令类型 16进制
     * @param data         数据
     * @param reverseRsCtl 代理客户端发送数据时需要反转
     * @return 数据帧字节数组
     */
    public static byte[] getByte(int cmd, byte[] data, boolean reverseRsCtl) {
        byte[] stx = ByteUtils.hexToBytes(ByteUtils.intToHex(STX, ProtocolConstants.STX_SIZE));
        String rsCtlHex = ByteUtils.intToHex(getRsCtl(), ProtocolConstants.RS_CTL_SIZE);
        if (reverseRsCtl) {
            rsCtlHex = new StringBuilder(rsCtlHex)
                    .reverse()
                    .toString();
        }
        byte[] rsCtl = ByteUtils.hexToBytes(rsCtlHex);
        byte[] cmdType = ByteUtils.hexToBytes(ByteUtils.intToHex(cmd, ProtocolConstants.CMD_TYPE_SIZE));
        byte[] length = ByteUtils.hexToBytes(ByteUtils.intToHex(data.length, ProtocolConstants.getLengthSize()));
        byte[] bytes = ByteUtils.mergeArrays(rsCtl, cmdType, length, data);
        byte bcc = ByteUtils.getBcc(bytes);
        return ByteUtils.mergeArrays(stx, bytes, new byte[]{bcc});
    }

    /**
     * 解析数据帧报文
     *
     * @param bytes 接收数据帧字节数组
     * @return 解析后的数据帧报文
     */
    public static ProxyMessage getProxyMessage(byte[] bytes) {
        ProxyMessage proxyMessage = new ProxyMessage();
        proxyMessage.setStx(ByteUtils.bytesToHex(Arrays.copyOfRange(bytes,
                0,
                ProtocolConstants.STX_SIZE)));
        proxyMessage.setRsCtl(ByteUtils.bytesToHex(Arrays.copyOfRange(bytes, ProtocolConstants.STX_SIZE,
                ProtocolConstants.STX_SIZE + ProtocolConstants.RS_CTL_SIZE)));
        proxyMessage.setCmdType(ByteUtils.bytesToHex(Arrays.copyOfRange(bytes,
                ProtocolConstants.STX_SIZE + ProtocolConstants.RS_CTL_SIZE,
                ProtocolConstants.STX_SIZE + ProtocolConstants.RS_CTL_SIZE + ProtocolConstants.CMD_TYPE_SIZE)));
        proxyMessage.setLength(ByteUtils.bytesToHex(Arrays.copyOfRange(bytes,
                ProtocolConstants.STX_SIZE + ProtocolConstants.RS_CTL_SIZE + ProtocolConstants.CMD_TYPE_SIZE,
                ProtocolConstants.STX_SIZE + ProtocolConstants.RS_CTL_SIZE + ProtocolConstants.CMD_TYPE_SIZE + ProtocolConstants.getLengthSize())));
        proxyMessage.setData(ByteUtils.bytesToHex(Arrays.copyOfRange(bytes,
                ProtocolConstants.STX_SIZE + ProtocolConstants.RS_CTL_SIZE + ProtocolConstants.CMD_TYPE_SIZE + ProtocolConstants.getLengthSize(),
                ProtocolConstants.STX_SIZE + ProtocolConstants.RS_CTL_SIZE + ProtocolConstants.CMD_TYPE_SIZE + ProtocolConstants.getLengthSize() + Integer.parseInt(ByteUtils.bytesToHex(Arrays.copyOfRange(bytes,
                        ProtocolConstants.STX_SIZE + ProtocolConstants.RS_CTL_SIZE + ProtocolConstants.CMD_TYPE_SIZE,
                        ProtocolConstants.STX_SIZE + ProtocolConstants.RS_CTL_SIZE + ProtocolConstants.CMD_TYPE_SIZE + ProtocolConstants.getLengthSize())), 16))));
        proxyMessage.setBcc(ByteUtils.bytesToHex(Arrays.copyOfRange(bytes, bytes.length - ProtocolConstants.BCC_SIZE, bytes.length)));
        return proxyMessage;
    }

    /**
     * 验证bcc
     *
     * @param bytes 接收数据帧字节数组
     * @return true 验证通过,false 验证失败
     */
    public static boolean checkBcc(byte[] bytes) {
        byte checkBcc = ByteUtils.getBcc(Arrays.copyOfRange(bytes, ProtocolConstants.STX_SIZE, bytes.length - ProtocolConstants.BCC_SIZE));
        byte bcc = Arrays.copyOfRange(bytes, bytes.length - ProtocolConstants.BCC_SIZE, bytes.length)[0];
        return bcc == checkBcc;
    }
}
